﻿using System;
using System.Transactions;

namespace Bricks.Data
{

    /// <summary>
    /// 
    /// </summary>
    public static class UnitOfWork
    {

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public static bool IsAlive()
        {
            return UnitOfWorkFoundation<IContextFacade, IContextFacadeFactory>.IsAlive();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static bool IsAlive(string key)
        {
            return UnitOfWorkFoundation<IContextFacade, IContextFacadeFactory>.IsAlive(key);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="action"></param>
        public static void Transact(Action action)
        {
            Transact<bool>(
                () =>
                {
                    action.Invoke();

                    return true;
                });
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="action"></param>
        /// <returns></returns>
        public static TResult Transact<TResult>(Func<TResult> action)
        {
            using (TransactionScope transaction = new TransactionScope())
            {
                TResult result = action.Invoke();

                transaction.Complete();

                return result;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="action"></param>
        public static void Transact(Action<IContextFacade> action)
        {
            Transact<bool>(
                contextFacade =>
                {
                    action.Invoke(contextFacade);

                    return true;
                });
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="action"></param>
        public static void Transact(string key, Action<IContextFacade> action)
        {
            Transact<bool>(key,
                contextFacade =>
                {
                    action.Invoke(contextFacade);

                    return true;
                });
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="action"></param>
        /// <returns></returns>
        public static TResult Transact<TResult>(Func<IContextFacade, TResult> action)
        {
            return Run<TResult>(contextFacade => contextFacade.Transact<TResult>(() => action.Invoke(contextFacade)));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="key"></param>
        /// <param name="action"></param>
        /// <returns></returns>
        public static TResult Transact<TResult>(string key, Func<IContextFacade, TResult> action)
        {
            return Run<TResult>(key, contextFacade => contextFacade.Transact<TResult>(() => action.Invoke(contextFacade)));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="action"></param>
        public static void Run(Action<IContextFacade> action)
        {
            UnitOfWorkFoundation<IContextFacade, IContextFacadeFactory>.Run(action);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="action"></param>
        public static void Run(Action<Func<IContextFacade>> action)
        {
            UnitOfWorkFoundation<IContextFacade, IContextFacadeFactory>.Run(action);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="action"></param>
        public static void Run(string key, Action<IContextFacade> action)
        {
            UnitOfWorkFoundation<IContextFacade, IContextFacadeFactory>.Run(key, action);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="action"></param>
        public static void Run(string key, Action<Func<IContextFacade>> action)
        {
            UnitOfWorkFoundation<IContextFacade, IContextFacadeFactory>.Run(key, action);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="action"></param>
        /// <returns></returns>
        public static TResult Run<TResult>(Func<IContextFacade, TResult> action)
        {
            return UnitOfWorkFoundation<IContextFacade, IContextFacadeFactory>.Run<TResult>(action);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="action"></param>
        /// <returns></returns>
        public static TResult Run<TResult>(Func<Func<IContextFacade>, TResult> action)
        {
            return UnitOfWorkFoundation<IContextFacade, IContextFacadeFactory>.Run<TResult>(action);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="key"></param>
        /// <param name="action"></param>
        /// <returns></returns>
        public static TResult Run<TResult>(string key, Func<IContextFacade, TResult> action)
        {
            return UnitOfWorkFoundation<IContextFacade, IContextFacadeFactory>.Run<TResult>(key, action);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="key"></param>
        /// <param name="action"></param>
        /// <returns></returns>
        public static TResult Run<TResult>(string key, Func<Func<IContextFacade>, TResult> action)
        {
            return UnitOfWorkFoundation<IContextFacade, IContextFacadeFactory>.Run<TResult>(key, action);
        }
    }
}
